package org.apache.hop.pipeline.transforms.script;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import org.apache.hop.core.Const;
import org.apache.hop.core.logging.HopLogStore;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.RowDataUtil;
import org.json.JSONObject;

public class ShellScriptEngine extends AbstractScriptEngine {
  public String cmd_type = "cpython";
  protected ILogChannel log = HopLogStore.getLogChannelFactory().create(this);

  // add by bzm
  private String executePythonScript(String cmd, String scriptPath) throws Exception {
    // List<String> command = Arrays.asList("python", scriptPath);
    System.out.println("[executePythonScript] cmd=" + cmd + " " + scriptPath);
    List<String> command = Arrays.asList(cmd, scriptPath);
    ProcessBuilder processBuilder = new ProcessBuilder(command);
    processBuilder.redirectErrorStream(true);

    Process process = processBuilder.start();
    // 读取标准输出流
    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
    StringBuilder output = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
      output.append(line).append("\n");
    }
    System.out.println("[executePythonScript] output=" + output);
    // 等待Python进程结束
    int exitCode = process.waitFor();
    if (exitCode == 0) {
      return output.toString();
    }
    return "";
  }

  @Override
  public Object eval(String script, Bindings bindings) throws ScriptException {
    // 将bindings中的参数替换到脚本中
    IRowMeta input = (IRowMeta) bindings.get("rowMeta");
    int szInput = input.size();
    StringBuilder param = new StringBuilder();
    for (int i = 0; i < szInput; i++) {
      String key = input.getValueMeta(i).getName();
      System.out.println("[eval] key=" + key);
      Object val = bindings.get(key);
      if (val == null) continue;
      // 字符串
      if (cmd_type.equals("shell")) {
        // 可以添加多行字符串
        param
            .append(key)
            .append(" =$(cat <<EOF")
            .append("\r\n")
            .append(val)
            .append("\r\n")
            .append("EOF")
            .append("\r\n")
            .append(")")
            .append("\r\n");
      } else {
        if (input.getValueMeta(i).getType() == 2) {
          param.append(key).append(" = '''").append(val).append("'''\r\n");
        } else {
          param.append(key).append(" = ").append(val).append("\r\n");
        }
      }
    }
    //    for (String key : bindings.keySet()) {
    //      System.out.println("[bzm]kye="+key);
    //    }
    script = param + script;
    // add by bzm
    // 1. 生成随机文件名
    String cmd = "python3";
    String fileName = "py" + UUID.randomUUID();
    fileName = "py";
    Path tempScript = null;
    try {
      try {
        if (cmd_type.equals("shell")) {
          tempScript = Files.createTempFile(fileName, ".sh");
          cmd = tempScript.toString();
          Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("rwxrwxrwx");
          Files.setPosixFilePermissions(tempScript, permissions);
          tempScript.toFile().setExecutable(true); // 设置可执行权限
        } else if (cmd_type.equals("大模型agent")) {
          cmd = "llm_agent";
        } else {
          tempScript = Files.createTempFile(fileName, ".py");
          cmd = "python3";
          // 自动加apibase对象
          script =
              "# -*- coding: utf-8 -*-\nimport os,sys,json\n"
                  + "sys.path.append('${FUNCTION_HOME}')\n"
                  + "from api.api_tools import apiBase,apiTools\n"
                  + script;
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      System.out.println("[ShellScriptEngine] script=" + script);
      // 替换script里面的${PROJECT_HOME}目录
      if (!"llm_agent".equals(cmd)) {
        if (tempScript == null) return "tempScript path error";
        String prjDir = Const.HOP_CONFIG_FOLDER + "/projects/samples";
        script = script.replaceAll("\\$\\{PROJECT_HOME}", prjDir);
        String function_dir =
            Const.HOP_CONFIG_FOLDER.substring(0, Const.HOP_CONFIG_FOLDER.indexOf("webapps/"))
                + "llm/qwne05";
        script = script.replaceAll("\\$\\{FUNCTION_HOME}", function_dir);

        System.out.println("[ShellScriptEngine] script=" + script);
        // 2. 将Python字符串写入到临时目录中的文件
        Files.writeString(tempScript, script);
        // 2. 设置权限（仅限 POSIX 系统，如 Linux/macOS）
        // tempScript.toFile().deleteOnExit(); // 程序退出时自动删除
        System.out.println("[ShellScriptEngine]tempFile= " + tempScript);
      }
      // 3. 运行Python文件
      String ret = "";
      if (cmd_type.equals("shell")) {
        ret = executePythonScript(cmd, " 11 ");
      } else if (cmd_type.equals("大模型agent")) {
        ret = Const.llmdb_api("tol_agent_json", new String[] {script});
      } else {
        ret = executePythonScript(cmd, tempScript.toString());
      }
      System.out.println("[ShellScriptEngine] ret=" + ret);
      log.logBasic(ret);
      IRowMeta out = (IRowMeta) bindings.get("outputRowMeta");
      if (szInput == 0) return ret;
      Object[] outObj = RowDataUtil.allocateRowData(szInput);
      JSONObject jsonObject;
      try {
        String marker = "===output===";
        int index = ret.indexOf(marker);
        if (index != -1) {
          ret = ret.substring(index + marker.length());
        }
        ret = ret.replace("\\\"", "\""); // 去除转义字符
        if (ret.startsWith("\"") && ret.length() > 2) {
          ret = ret.substring(1, ret.length() - 1);
        }
        log.logBasic(ret);
        jsonObject = new JSONObject(ret);
        // 必须要加一个result输入参数，不然没有参数输出
        for (int i = 0; i < szInput; i++) {
          String key = input.getValueMeta(i).getName();
          int type = input.getValueMeta(i).getType();
          log.logBasic("param key=" + key + ";type = " + type);
          if (!jsonObject.has(key)) {
            log.logBasic("key=" + key + " 不在返回的json里面");
            outObj[i] = bindings.get(key);
            continue;
          }
          // 需要参考RandomValue类的 private Object[] getRandomValue(IRowMeta inputRowMeta, Object[]
          // inputRowData) {
          switch (type) {
            case 2:
              outObj[i] = jsonObject.getString(key);
              log.logBasic("param key=" + key + ";type = " + type + ";val=" + outObj[i]);
              break;
            case 5:
              outObj[i] = (long) jsonObject.getInt(key);
              log.logBasic("param key=" + key + ";type = " + type + ";val=" + outObj[i]);
              break;
          }
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
      Script sc = (Script) bindings.get("transform");
      sc.putRow(out, outObj);
      return ret;
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      if (tempScript != null) tempScript.toFile().delete();
    }
  }

  @Override
  public Object eval(String script, ScriptContext context) throws ScriptException {
    throw new UnsupportedOperationException();
  }

  @Override
  public Object eval(Reader reader, ScriptContext context) throws ScriptException {
    throw new UnsupportedOperationException();
  }

  @Override
  public Bindings createBindings() {
    return new SimpleBindings();
  }

  @Override
  public ScriptEngineFactory getFactory() {
    return new ShellScriptEngineFactory();
  }

  public class Main {
    public static void main(String[] args) {
      ScriptEngineManager manager = new ScriptEngineManager();
      ScriptEngine engine = manager.getEngineByName("cpython");

      if (engine == null) {
        System.err.println("Shell script engine not found.");
        return;
      }

      try {
        String script = "echo Hello, World!";
        String result = (String) engine.eval(script);
        System.out.println("Script Output: " + result);
      } catch (ScriptException e) {
        e.printStackTrace();
      }
    }
  }
}
